package net.oschina.allchat.message.processing.json.parsers.im;

import java.util.ArrayList;
import java.util.List;

import net.oschina.allchat.message.processing.Attribute;
import net.oschina.allchat.message.processing.ElementParserAdaptor;
import net.oschina.allchat.message.processing.IElementParser;
import net.oschina.allchat.message.processing.IParser;
import net.oschina.allchat.message.processing.IParserFactory;
import net.oschina.allchat.message.processing.IParsingContext;
import net.oschina.allchat.message.processing.json.ParsingUtils;
import net.oschina.allchat.message.processing.json.parsers.core.StanzaParser;
import net.oschina.allchat.protocol.HandyUtils;
import net.oschina.allchat.protocol.core.LangText;
import net.oschina.allchat.protocol.core.Protocol;
import net.oschina.allchat.protocol.core.ProtocolException;
import net.oschina.allchat.protocol.core.stanza.error.BadRequest;
import net.oschina.allchat.protocol.im.stanza.Message;

public class MessageParserFactory implements IParserFactory<Message> {
	private static final String VALUE_TYPE_NORMAL = "normal";
	private static final String VALUE_TYPE_CHAT = "chat";
	private static final String VALUE_TYPE_GROUP_CHAT = "groupchat";
	private static final String VALUE_TYPE_HEADLINE = "headline";
	
	private static final String PATH_MESSAGE_SUBJECTS = "/subjects";
	private static final String PATH_MESSAGE_SUBJECT = "/subjects/[]";
	private static final String PATH_MESSAGE_BODIES = "/bodies";
	private static final String PATH_MESSAGE_BODY = "/bodies/[]";
	private static final String PATH_MESSAGE_THREAD = "/thread";
	
	private static final Object KEY_LANG_TEXT = new Object();
	
	@Override
	public Protocol getProtocol() {
		return Message.PROTOCOL;
	}

	@Override
	public IParser<Message> create() {
		return new StanzaParser<Message>() {

			@Override
			public Message createObject() {
				return new Message();
			}

			@Override
			protected IElementParser<Message> doGetElementParser(String parsingPath) {
				if (PATH_MESSAGE_SUBJECTS.equals(parsingPath)) {
					return new ElementParserAdaptor<Message>() {
						@Override
						public void processAttributes(IParsingContext<Message> context, List<Attribute<?>> attributes) {
							super.processAttributes(context, attributes);
							List<LangText> subjects = new ArrayList<LangText>();
							context.getObject().setSubjects(subjects);
						}
					};
				} else if (PATH_MESSAGE_SUBJECT.equals(parsingPath)) {
					return new IElementParser<Message>() {
						@Override
						public void processText(IParsingContext<Message> context, String text) {
							if (HandyUtils.isBlank(text)) {
								throw new ProtocolException(new BadRequest("subject text is null"));
							}
							
							LangText langText = context.removeAttribute(KEY_LANG_TEXT);
							if (langText == null) {
								throw new RuntimeException("null LangText???");
							}
							
							langText.setText(text);
						}
						
						@Override
						public void processAttributes(IParsingContext<Message> context, List<Attribute<?>> attributes) {
							LangText langText = new LangText(null, ParsingUtils.processLangTextAttributes(attributes));
							context.getObject().getSubjects().add(langText);
							context.setAttribute(KEY_LANG_TEXT, langText);
						}
					};
				} else if (PATH_MESSAGE_BODIES.equals(parsingPath)) {
					return new ElementParserAdaptor<Message>() {
						@Override
						public void processAttributes(IParsingContext<Message> context, List<Attribute<?>> attributes) {
							super.processAttributes(context, attributes);
							List<LangText> bodies = new ArrayList<LangText>();
							context.getObject().setBodies(bodies);
						}
					};
				} else if (PATH_MESSAGE_BODY.equals(parsingPath)) {
					return new IElementParser<Message>() {
						@Override
						public void processText(IParsingContext<Message> context, String text) {
							if (HandyUtils.isBlank(text)) {
								throw new ProtocolException(new BadRequest("body text is null"));
							}
							
							LangText langText = context.removeAttribute(KEY_LANG_TEXT);
							if (langText == null) {
								throw new RuntimeException("null LangText???");
							}
							
							langText.setText(text);
						}
						
						@Override
						public void processAttributes(IParsingContext<Message> context, List<Attribute<?>> attributes) {
							LangText langText = new LangText(null, ParsingUtils.processLangTextAttributes(attributes));
							context.getObject().getBodies().add(langText);
							context.setAttribute(KEY_LANG_TEXT, langText);
						}
					};
				} else if (PATH_MESSAGE_THREAD.equals(parsingPath)) {
					return new ElementParserAdaptor<Message>() {
						@Override
						public void processText(IParsingContext<Message> context, String text) {
							if (HandyUtils.isBlank(text)) {
								throw new ProtocolException(new BadRequest("null thread"));
							}
							
							context.getObject().setThread(text);
						}
					};
				} else {
					return null;
				}
			}

			@Override
			protected void processType(IParsingContext<Message> context, String value) {
				if (VALUE_TYPE_NORMAL.equals(value)) {
					context.getObject().setType(Message.Type.NORMAL);
				} else if (VALUE_TYPE_CHAT.equals(value)) {
					context.getObject().setType(Message.Type.CHAT);
				} else if (VALUE_TYPE_GROUP_CHAT.equals(value)) {
					context.getObject().setType(Message.Type.GROUP_CHAT);
				} else if (VALUE_TYPE_HEADLINE.equals(value)) {
					context.getObject().setType(Message.Type.HEADLINE);
				} else {
					throw new ProtocolException(new BadRequest(String.format("invalid message type '%s'", value)));
				}
			}
		};
	}

}
